﻿using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WinFileTransfer
{
    public class SystemIcon
    {
        private static System.Collections.Generic.Dictionary<String, Icon> kvIcon = new System.Collections.Generic.Dictionary<String, Icon>();

        /// <summary>
        /// 获得指定文件图标句柄
        /// </summary>
        /// <param name="path">指定的文件名</param>
        /// <param name="fileattribute">文件属性</param>
        /// <param name="?">返回的文件信息</param>
        /// <param name="SizeFileInfo">sfinfo的比特值</param>
        /// <param name="flag">指明要返回的文件信息标识符</param>
        /// <returns>文件的图标句柄</returns>
        [DllImport("shell32.dll", EntryPoint = "SHGetFileInfo")]
        public static extern IntPtr SHGetFileInfo(string path, uint fileattribute, ref SHFILEINFO sfinfo
              , uint SizeFileInfo, uint flag);

        /// <summary>
        /// 图标结构
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]//自定义类型
        public struct SHFILEINFO
        {
            public IntPtr hIcon;//文件的图标句柄
            public IntPtr iIcon;//图标的系统索引号
            public uint aattributes;//文件的属性值
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]//MarshalAs只是如何在托管代码和非托管代码间传送数据
            public string displayname;//文件的显示名
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string typename;//文件的类型
        }

        /// <summary>
        /// 清除图标
        /// </summary>
        /// <param name="hIcon">图标句柄</param>
        /// <returns>返回非零表示成功，零表示失败</returns>
        [DllImport("user32.dll", EntryPoint = "DestroyIcon")]
        public static extern int DestroyIcon(IntPtr hIcon);

        /// <summary>
        /// 获取指定路径的系统图标
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="isFolder">表示是否为获取文件夹图标，true为获取文件夹图标，false为获取文件图标</param>
        public static Icon GetSysIcon(FileSystemInfo info)
        {
            Icon icon = null;
            if (info is DirectoryInfo)
            {
                if (kvIcon.ContainsKey("文件夹"))
                    icon = kvIcon["文件夹"];
                else
                {
                    switch (info.Name.ToUpper())
                    {
                        case "RECYCLER":
                        case "RECYCLED":
                        case "SYSTEM VOLUME INFORMATION":
                        case "$RECYCLE.BIN":
                            break;
                        default:
                            SHFILEINFO shfileinfo = new SHFILEINFO();
                            SHGetFileInfo(info.FullName, (uint)0x80, ref shfileinfo,
                                (uint)Marshal.SizeOf(shfileinfo), (uint)(0x100 | 0x400));//取得icon和typename
                            icon = Icon.FromHandle(shfileinfo.hIcon).Clone() as Icon;
                            DestroyIcon(shfileinfo.hIcon);
                            kvIcon.Add("文件夹", icon);
                            break;
                    }
                }
            }
            else
            {
                if (kvIcon.ContainsKey(info.Extension))
                    icon = kvIcon[info.Extension];
                else
                    try
                    {
                        icon = Icon.ExtractAssociatedIcon(info.FullName);
                        if(!info.Extension.Equals(".lnk"))
                            kvIcon.Add(info.Extension, icon);
                    }
                    catch (ArgumentException e1)
                    {
                        switch (info.Name.ToUpper())
                        {
                            case ".sys":
                            case ".bin":
                            case ".com":
                                break;
                            default:
                                SHFILEINFO shfileinfo = new SHFILEINFO();
                                SHGetFileInfo(info.FullName, (uint)0x80, ref shfileinfo,
                                    (uint)Marshal.SizeOf(shfileinfo), (uint)(0x100 | 0x400));
                                icon = Icon.FromHandle(shfileinfo.hIcon).Clone() as Icon;
                                DestroyIcon(shfileinfo.hIcon);
                                if(!info.Extension.Equals(".lnk"))
                                    kvIcon.Add(info.Extension, icon);
                                break;
                        }
                    }
                    catch (Exception e2)
                    {
                        LogHelper.Log.Error(e2);
                    }
            }
            return icon;
        }

    }
}
